CSS in JS 解決了 CSS 命名的問題。
由於 component-based 的概念興起元件開發成為顯學,CSS in JS 提供了將樣式寫在元件中解決方案,也讓 CSS 需要從寫程式語言的角度去進行架構設計。
CSS in JS 不僅降低了維護難度也加速了開發速度,減少檔案切換和減少 class 命名錯誤等等問題,常見的 library 像是 css module、vanilla-extract、styled-components、styled-jsx (Next.js) 都非常好上手,更完整的將元件模組化並增加可重用性。
CSS in JS 缺點也要先說在前面,當需要 Server Render 時,相關的效能問題也需要一併考慮進去。
CSS in JS 像是把需要打扮的道具跟裝備直接跟使用的情境整合在一起,像是約會必勝穿搭、適合上班的裝容等等,在遇到相關情境時能夠輕鬆應對。
@extend
或 @mixin
這樣的寫法,需把元件切的夠小,才會有一定程度的共用性styled-components 提供了在 JavaScript 中直接撰寫 CSS 的介面,意味著可以使用所有的 CSS 功能,切換主視覺要多用一個 <ThemeProvider>
,傳入的 Props 差異太大時有點麻煩
import styled from "styled-components";
function Sample() {
const StyledButton = styled.button`
color: #ffffff;
font-size: 20px;
border-radius: 5px;
`;
return <StyledButton type="button">按鈕</StyledButton>;
}
styled-components 也提供了主視覺的配置,透過 styled-components 提供的 ThemeProvider 在外層注入就可以在元件中直接取值。
import { ThemeProvider } from "styled-components";
const colors = {
primary: "#c18e00",
secondary: "#0086ff",
dark: "rgba(0, 0, 0, 0.6)",
muted: "rgba(0, 0, 0, 0.3)",
light: "rgba(0, 0, 0, 0.18)",
};
const fontSizes = {
xl: `${1.875 * base}rem`,
lg: `${1.375 * base}rem`,
md: `${1.25 * base}rem`,
base: `${1 * base}rem`,
sm: `${0.875 * base}rem`,
xs: `${0.75 * base}rem`,
};
const theme = {
colors,
fontSizes,
};
class MyApp extends App {
componentDidMount() {
objectFitImages();
}
render() {
const { Component, pageProps, reduxStore } = this.props;
return (
<ThemeProvider theme={theme}>
<Provider store={reduxStore}>
<Component {...pageProps} />
</Provider>
</ThemeProvider>
);
}
}
const StyleWrapper = styled.div`
background: ${({ color, reverse, theme: { colors } }) =>
reverse ? colors[color] : "none"};
`;
function TestMessage({ color, reverse, message }) {
return (
<StyleWrapper color={color} reverse={reverse}>
<span>{message}</span>
</StyleWrapper>
);
}
由於 styled-components 提供了 function 的撰寫模式,所以即使撰寫 RWD 的元件也很簡單。
function getWidthString(span) {
let result;
if (span) {
result = `width: ${(span / 12) * 100}%`;
}
return result;
}
const Column = styled.div`
float: left;
width: 100%;
/* stylelint-disable value-keyword-case */
${({ xs }) => (xs ? getWidthString(xs) : "width: 100%")};
@media only screen and (min-width: 768px) {
${({ sm }) => sm && getWidthString(sm)};
}
@media only screen and (min-width: 992px) {
${({ md }) => md && getWidthString(md)};
}
@media only screen and (min-width: 1200px) {
${({ lg }) => lg && getWidthString(lg)};
}
`;
styled-jsx 則是 Next.js 內建支援的介面,基礎的功能也是差不多,就是寫法上稍微不太相同。
function Sample() {
return (
<>
<style jsx>
{`
button {
color: #ffffff;
font-size: 20px;
border-radius: 5px;
}
`}
</style>
<button type="button">按鈕</button>
</>
);
}
global 的樣式,RWD 之類的就可以訂在這邊。
export default () => (
<div>
<style jsx global>{`
body {
background: red;
}
`}</style>
</div>
);
動態的寫法,跟 styled-components 可以做到判斷,但又沒有 function 那麼彈性。
const Button = (props) => (
<button>
Hello
<style jsx>{`
button {
padding: ${"large" in props ? "50" : "20"}px;
background: ${props.theme.background};
}
`}</style>
</button>
);
CSS Modules 是用來解決 CSS 重複命名需要時常處理衝突的問題,在 Create React App 中 CSS 命名規則為 {檔名}.module.css
。
main.module.css
.information {
color: red;
}
page.module.css
.information {
color: green;
}
import styleMain from "./main.module.css";
import stylePage from "./page.module.css";
export default function Test() {
return (
<div>
<h1 className={styleMain.information}>App</h1>
<h3 className={stylePage.information}>Test</h1>
</div>
);
}
在 Class 的命名用駝峰式會較佳,但沒有一定。
style["class-name"];
style.className;